package cn.virens.common.fastjson.serializer;

import cn.hutool.core.date.DateUtil;
import cn.virens.common.exception.APIException;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.writer.ObjectWriter;

import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.Date;
import java.util.Objects;
import java.util.function.BiFunction;

public final class LocalDateTimeSerializer implements ObjectWriter<Object>, BiFunction<String, Object, Object> {
    public final static LocalDateTimeSerializer instance = new LocalDateTimeSerializer();

    private static final String PATTERN_3 = "HH:mm:ss";
    private static final String PATTERN_2 = "yyyy-MM-dd";
    private static final String PATTERN_1 = "yyyy-MM-dd HH:mm:ss";

    private static final DateTimeFormatter FORMATTER_1 = DateTimeFormatter.ofPattern(PATTERN_1);
    private static final DateTimeFormatter FORMATTER_2 = DateTimeFormatter.ofPattern(PATTERN_2);
    private static final DateTimeFormatter FORMATTER_3 = DateTimeFormatter.ofPattern(PATTERN_3);

    private LocalDateTimeSerializer() {
    }

    @Override
    public void write(JSONWriter jsonWriter, Object fieldObject, Object fieldName, Type fieldType, long features) {
        if (jsonWriter != null && fieldObject != null && fieldObject instanceof Temporal value) {
            jsonWriter.writeString(apply(Objects.toString(fieldName), value).toString());

            return;
        }

        if (jsonWriter != null && fieldObject != null && fieldObject instanceof Date value) {
            jsonWriter.writeString(apply(Objects.toString(fieldName), value).toString());

            return;
        }

        jsonWriter.writeNull();

    }

    @Override
    public Object apply(String name, Object object) throws APIException {
        if (object instanceof LocalDateTime value) return format1(name, value);
        if (object instanceof LocalDate value) return format2(name, value);
        if (object instanceof LocalTime value) return format3(name, value);

        if (object instanceof java.sql.Timestamp value) return format1(name, value);
        if (object instanceof java.sql.Date value) return format2(name, value);
        if (object instanceof java.sql.Time value) return format3(name, value);
        if (object instanceof Date value) return format1(name, value);

        return object;
    }

    private static String format3(String name, Date value) {
        return DateUtil.format(value, PATTERN_3);
    }

    private static String format3(String name, LocalTime value) {
        return FORMATTER_3.format(value);
    }

    private static String format2(String name, Date value) {
        return DateUtil.format(value, PATTERN_2);
    }

    private static String format2(String name, LocalDate value) {
        return FORMATTER_2.format(value);
    }

    private static String format1(String name, Date value) {
        return DateUtil.format(value, PATTERN_1);
    }

    private static String format1(String name, LocalDateTime value) {
        return FORMATTER_1.format(value);
    }
}
